﻿using System;
using System.Data.Common;
using System.Linq;

namespace Centido.Management.ConsoleManager
{
    /// <summary>
    ///   A console command that deletes the specified user from the current domain
    /// or removes the user from the specified security role / business unit.
    /// </summary>
    internal class DeleteUserCommand : Command
    {
        /// <summary>
        ///   The user name parameter.
        /// </summary>
        public const string UserNameParameter = "user";

        /// <summary>
        ///   The user name parameter (short name).
        /// </summary>
        public const string UserNameShortParameter = "u";

        /// <summary>
        ///   The role name parameter.
        /// </summary>
        public const string RoleNameParameter = "parentrole";

        /// <summary>
        ///   The role name parameter (short name).
        /// </summary>
        public const string RoleNameShortParameter = "pr";

        /// <summary>
        ///   The unit name parameter.
        /// </summary>
        public const string UnitNameParameter = "parentunit";

        /// <summary>
        ///   The unit name parameter (short name).
        /// </summary>
        public const string UnitNameShortParameter = "pu";


        /// <summary>
        ///   Gets the console command name.
        /// </summary>
        public override string Name
        {
            get { return "deleteuser"; }
        }


        /// <summary>
        ///   Gets the console command description.
        /// </summary>
        public override string Description
        {
            get { return Messages.DeleteUserCommandDescription; }
        }


        /// <summary>
        ///   Gets the console command full description.
        /// </summary>
        public override string FullDescription
        {
            get { return Messages.DeleteUserCommandFullDescription; }
        }


        /// <summary>
        ///   Executes the console command.
        /// </summary>
        /// <param name="context">The console command execution context.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="context"/> is null.</exception>
        public override void Execute(CommandExecutionContext context)
        {
            base.Execute(context);

            // If the user name was not specified
            if (!context.ParameterValueIsNotEmpty(UserNameParameter, UserNameShortParameter))
            {
                Console.WriteLine(Messages.DeleteUserCommandNotAllParametersSpecified);
                return;
            }

            var domain = context.CurrentDomain;

            if (domain == null) return;

            // If the current user has no permission to perform this action
            if (!domain.CurrentUser.CanChangeSecurity)
            {
                Console.WriteLine(Messages.NeedCanChangeSecurityPermissionMessage);
                return;
            }

            // The user name
            var userName = context.GetParameterValue(UserNameParameter, UserNameShortParameter);

            try
            {
                // Trying to find the specified user
                var user = domain.GetUser(userName);

                // If there is no user with the specified name
                if (user == null)
                {
                    Console.WriteLine(Messages.CannotFindUserError, userName);
                    return;
                }

                // If the role name was specified
                if (context.ParameterValueIsNotEmpty(RoleNameParameter, RoleNameShortParameter))
                {
                    // ... then deleting the user from the role

                    // The role name
                    var roleName = context.GetParameterValue(RoleNameParameter, RoleNameShortParameter);

                    // Trying to find the role with the specified name
                    var role = domain.GetRole(roleName);

                    // If there is no role with the specified name
                    if (role == null)
                    {
                        Console.WriteLine(Messages.CannotFindRoleError, roleName);
                        return;
                    }

                    if (role.ContainsUser(user))
                        role.RemoveUser(user);
                }

                // If the unit name was specified
                if (context.ParameterValueIsNotEmpty(UnitNameParameter, UnitNameShortParameter))
                {
                    // ... then deleting the user from the unit

                    // The unit name
                    var unitName = context.GetParameterValue(UnitNameParameter, UnitNameShortParameter);

                    // Trying to find a unit with the specified name
                    var unit = domain.GetUnit(unitName);

                    // If there is no unit with the specified name
                    if (unit == null)
                    {
                        Console.WriteLine(Messages.CannotFindUnitError, unitName);
                        return;
                    }

                    if (unit.Users.Any(u => u.Name == user.Name))
                        unit.RemoveUser(user);
                }

                // If no unit or role parameter were specified
                if (!context.ParameterValueIsNotEmpty(UnitNameParameter, UnitNameShortParameter)
                    && !context.ParameterValueIsNotEmpty(RoleNameParameter, RoleNameShortParameter))
                {
                    // ... then deleting the user
                    user.Delete();
                }
            }
            catch (DbException e)
            {
                Console.WriteLine(e.Message);
                Console.WriteLine();
                return;
            }

            // Displaying the success message
            Console.WriteLine(Messages.CommandCompletedMessage);
        }
    }
}
